//这是个TCP 服务器
#include"Socket.hpp"
#include<iostream>
#include<memory>
#include<sys/wait.h>
#include<functional>

using namespace SocketModule;
using namespace LogModule;

//TCP服务主要交给上层，让上层做io
//这就生成一个IO服务，要求传套接字和client
using ioservice_t = std::function<void(std::shared_ptr<Socket> &sock,InetAddr &client)>;


//主要解决：连接的问题    IO通信的问题
//细节：TcpServer  不需要关心自己未来传递的信息是什么    处理数据交给上层

//网络版本的计算机    长服务
class TcpServer
{
public:
    //构造     直接就创建出了一个携带listen套接字的服务(构建服务器的时候就要ioservice_t)
    TcpServer(uint16_t port,ioservice_t service):
        _port(port),
        _listensockptr(std::make_unique<TcpSocket>()),
        _isrunning(false),
        _service(service)
    {
        _listensockptr->BuildTcpSocketMethod(_port);
    }

    void Start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            InetAddr client;     

        //TCPServer内部只负责  获取新链接  创建子进程  执行回调  处理完退出  然后结束掉子进程

            //获取新链接(1.和client客户端通信的sockfd（文件描述符）   2.client的网络地址)
            auto sock = _listensockptr->Accept(&client);     //收到了一个套接字  也受到了client的信息（客户端是谁）
            
            
            if(sock == nullptr)
            {
                continue;    //智能指针可以直接和空指针比较   Accept失败
            }
            LOG(LogLevel::DEBUG) << "accept success .......";

            //sock && client
            pid_t id = fork();     //创建子进程
            if(id < 0)
            {
                LOG(LogLevel::FATAL) << "fork error ...";
                exit(FORK_ERR);
            }

        //父子进程返回的类型都是一个指针 socket       所以socket需要提供接口（close）   
            else if(id == 0)
            {
            //子进程  要关闭listensock    父子进程后续的操作时   都要把不需要的文件描述符关掉
                _listensockptr->Close();
                if(fork() > 0)
                    exit(0);    //子进程会继承父进程的sock 以及 client      子进程不用担心sock和client覆盖问题，因为写时拷贝
            //孙子进程在执行任务，已经是孤儿了
                _service(sock,client);    //孤儿进程进行ioservice
                exit(OK);   

            }
            else
            {
                //父进程   要关闭accept上来的sock
                sock->Close();
                pid_t rid = ::waitpid(id,nullptr,0);   //等待的是id   退出码不要nullptr   等待方式0   
                (void)rid;  //返回值也不要rid
            }



        }
        _isrunning = false;
    }

    ~TcpServer(){}

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listensockptr;   //监听socket指针
    bool _isrunning;
    ioservice_t _service;   //回调
};

